#include <cassert>                          // à inclure ds .h ?
#include <unistd.h>
#include "./data/FMOD/api/inc/fmod.h"

#include "sdljeu.h"
#include <stdio.h>
#include <stdlib.h>

const int TAILLE_SPRITE = 32;


void sdljeuInit(sdlJeu& sj, const char *niv)
{
	jeuInit( sj.jeu,niv );
	int dimx, dimy;

//recupere les dimensions du terrain, multipliées par le sprite
	dimx = getDimX(jeuGetTerrain(sj.jeu)) * TAILLE_SPRITE;
	dimy = getDimY(jeuGetTerrain(sj.jeu)) * TAILLE_SPRITE;

// pour l'ecran (on prend des dimensions plus grandes pour rajouter les options
	sj.ecran = SDL_SetVideoMode(  dimx + 300, dimy , 32, SDL_SWSURFACE );
	assert( sj.ecran );
	SDL_WM_SetCaption( "Tetris", NULL );

//pour le terrain
    sj.terrain = SDL_load_image("data/mare.bmp");
    if (!sj.terrain) sj.terrain = SDL_load_image("../data/mare.bmp");
	assert( sj.terrain );

// recupere l'image de la piece1
	sj.piece1 = SDL_load_image("data/canard1.bmp");
	SDL_SetColorKey(sj.piece1,SDL_SRCCOLORKEY,SDL_MapRGB(sj.ecran->format,0,255,0));
	if (!sj.piece1) sj.piece1 = SDL_load_image("../data/canard1.bmp");
	assert( sj.piece1 );

// recupere l'image de la piece2
	sj.piece2 = SDL_load_image("data/canard2.bmp");
	SDL_SetColorKey(sj.piece2,SDL_SRCCOLORKEY,SDL_MapRGB(sj.ecran->format,0,255,0));
	if (!sj.piece2) sj.piece2 = SDL_load_image("../data/canard2.bmp");
	assert( sj.piece2 );

// recupere l'image de la piece3
	sj.piece3 = SDL_load_image("data/canard3.bmp");
	SDL_SetColorKey(sj.piece3,SDL_SRCCOLORKEY,SDL_MapRGB(sj.ecran->format,0,255,0));
	if (!sj.piece3) sj.piece3 = SDL_load_image("../data/canard3.bmp");
	assert( sj.piece3 );

// recupere l'image de la piece4
	sj.piece4 = SDL_load_image("data/canard4.bmp");
	SDL_SetColorKey(sj.piece4,SDL_SRCCOLORKEY,SDL_MapRGB(sj.ecran->format,0,255,0));
	if (!sj.piece4) sj.piece4 = SDL_load_image("../data/canard4.bmp");
	assert( sj.piece4 );

// recupere l'image de la piece5
	sj.piece5 = SDL_load_image("data/canard5.bmp");
	SDL_SetColorKey(sj.piece5,SDL_SRCCOLORKEY,SDL_MapRGB(sj.ecran->format,0,255,0));
	if (!sj.piece5) sj.piece5 = SDL_load_image("../data/canard5.bmp");
	assert( sj.piece5 );

// recupere l'image de la piece6
	sj.piece6 = SDL_load_image("data/canard6.bmp");
	SDL_SetColorKey(sj.piece6,SDL_SRCCOLORKEY,SDL_MapRGB(sj.ecran->format,0,255,0));
	if (!sj.piece6) sj.piece6 = SDL_load_image("../data/canard6.bmp");
	assert( sj.piece6 );

// recupere l'image de la piece7
	sj.piece7 = SDL_load_image("data/canard7.bmp");
	SDL_SetColorKey(sj.piece7,SDL_SRCCOLORKEY,SDL_MapRGB(sj.ecran->format,0,255,0));
	if (!sj.piece7) sj.piece7 = SDL_load_image("../data/canard7.bmp");
	assert( sj.piece7 );

// recupere l'image du mur
	sj.mur = SDL_load_image("data/mur32.bmp");
	if (!sj.mur) sj.mur = SDL_load_image("../data/mur32.bmp");
	assert( sj.mur);

// recupere l'image pour la pause
    sj.pause = SDL_load_image("data/pause.bmp");
    SDL_SetColorKey(sj.pause,SDL_SRCCOLORKEY,SDL_MapRGB(sj.ecran->format,0,255,0));
	if (!sj.pause) sj.pause = SDL_load_image("../data/pause.bmp");
	assert( sj.pause);
}



void adljeuAff(sdlJeu& sj, bool pause)
{
    TTF_Font *police = NULL;
    TTF_Font *police2 = NULL;
    SDL_Rect position;
    SDL_Surface *texte = NULL;
    SDL_Surface *texte2 = NULL;
    SDL_Surface *texte_pause = NULL;
    SDL_Color couleurNoire = {24, 125, 100};
// pour la gauche du jeu
    char text[200];
    SDL_Surface *pieceS = NULL;
    SDL_Surface *Score = NULL;
    SDL_Surface *Score2 = NULL;
    SDL_Surface *NbrLigne = NULL;
    SDL_Surface *NbrLigne2 = NULL;
    SDL_Surface *Niveau = NULL;
    SDL_Surface *Niveau2 = NULL;


    int x2,y2; // pour parcourir les pieces
    int x,y; // pour parcourir le tableau

//Remplir l'écran de gris
	SDL_FillRect( sj.ecran, &sj.ecran->clip_rect, SDL_MapRGB( sj.ecran->format, 230, 230, 230 ) );

	const Terrain& ter = jeuGetTerrain(sj.jeu); // recupere le terrain de jeu

//pour le fond d'ecran du terrain
	SDL_apply_surface( sj.terrain, sj.ecran, 2*TAILLE_SPRITE, 4*TAILLE_SPRITE);

// pour les murs
        for(y=0 ; y<=YMAX-2 ; y++)
        {
            for(x=0 ; x<=XMAX-2 ; x++)
            {
                    if(terGetXY(ter,y,x)!='*' && y >= 4)
                    {
                        switch(terGetXY(ter,y,x))
                        {
                            case '|' :
                                SDL_apply_surface( sj.mur, sj.ecran, (1+x)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;

                            case '-' :
                                SDL_apply_surface( sj.mur, sj.ecran, (1+x)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;

                            case '1' :
                                SDL_apply_surface( sj.piece1, sj.ecran, (1+x)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;

                            case '2':
                                SDL_apply_surface( sj.piece2, sj.ecran, (1+x)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;

                            case '3' :
                                SDL_apply_surface( sj.piece3, sj.ecran, (1+x)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;

                            case '4' :
                                SDL_apply_surface( sj.piece4, sj.ecran, (1+x)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;

                            case '5' :
                                SDL_apply_surface( sj.piece5, sj.ecran, (1+x)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;

                            case '6' :
                                SDL_apply_surface( sj.piece6, sj.ecran, (1+x)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;

                            case '7' :
                                SDL_apply_surface( sj.piece7, sj.ecran, (1+x)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;

                        }
                    }
                //pour la piece courante
                    x2 = x - jeuGetPosX(sj.jeu);
                    y2 = y - jeuGetPosY(sj.jeu);

                    if (x2>=0 && x2<4 && y2>=0 && y2<4
                       && (SPiece[jeuGetPiece_courante(sj.jeu)][jeuGetRotation(sj.jeu)][4*y2+x2]!='0')
                          && y>=4)
                    {
                        switch(SPiece[jeuGetPiece_courante(sj.jeu)][jeuGetRotation(sj.jeu)][4*y2+x2])
                        {

                            case '1' :
                                SDL_apply_surface( sj.piece1, sj.ecran,TAILLE_SPRITE+(jeuGetPosX(sj.jeu)+x2)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;

                            case '2' :
                                SDL_apply_surface( sj.piece2, sj.ecran,TAILLE_SPRITE+(jeuGetPosX(sj.jeu)+x2)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;

                            case '3' :
                                SDL_apply_surface( sj.piece3, sj.ecran,TAILLE_SPRITE+(jeuGetPosX(sj.jeu)+x2)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;

                            case '4' :
                                SDL_apply_surface( sj.piece4, sj.ecran,TAILLE_SPRITE+(jeuGetPosX(sj.jeu)+x2)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;

                            case '5' :
                                SDL_apply_surface( sj.piece5, sj.ecran,TAILLE_SPRITE+(jeuGetPosX(sj.jeu)+x2)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;

                            case '6' :
                                SDL_apply_surface( sj.piece6, sj.ecran,TAILLE_SPRITE+(jeuGetPosX(sj.jeu)+x2)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;

                            case '7' :
                                SDL_apply_surface( sj.piece7, sj.ecran,TAILLE_SPRITE+(jeuGetPosX(sj.jeu)+x2)*TAILLE_SPRITE, (y)*TAILLE_SPRITE);
                                break;
                        }
                    }
            }
        }
//initialisation des polices
    police = TTF_OpenFont("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 25);  // ouvre la police
    assert(police != NULL);
    police2 = TTF_OpenFont("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf", 50);  // ouvre la police
    assert(police2 != NULL);

// commence le titre
    texte = TTF_RenderText_Blended(police, "TETRIS", couleurNoire);
    position.x = (1+getDimX(ter)/2-2) * TAILLE_SPRITE ;
    position.y = 0;
    SDL_BlitSurface(texte, NULL, sj.ecran, &position);  //Blit du texte par-dessus

    texte2 = TTF_RenderText_Blended(police, "Coins-Coins-Coins", couleurNoire);
    position.x = (getDimX(ter)/2-3) * TAILLE_SPRITE ;
    position.y = 1 *TAILLE_SPRITE;
    SDL_BlitSurface(texte2, NULL, sj.ecran, &position);  //Blit du texte par-dessus

// si c'est la pause, met la musique en pause, affiche un texte et l'image de pause
    if(pause == true)
    {
        FSOUND_SetPaused(FSOUND_ALL, 1); // On met en pause
        SDL_apply_surface( sj.pause, sj.ecran,2,TAILLE_SPRITE*7); // affiche l'image de pause
        SDL_Color couleur = {255, 165, 0}; // couleur de la pause
        texte_pause = TTF_RenderText_Blended(police2, "PAUSE", couleur);
        position.x = (1+getDimX(ter)/2) * TAILLE_SPRITE - 2*TAILLE_SPRITE-5 ;
        position.y = 5*TAILLE_SPRITE;
        SDL_BlitSurface(texte_pause, NULL, sj.ecran, &position);  //Blit du texte par-dessus
    }

// Si la chanson etait en pause et qu'on l'arrete
    if (FSOUND_GetPaused(1) && pause == false)
        {
            FSOUND_SetPaused(FSOUND_ALL, 0); // On enleve la pause
        }


// affichage de la piece suivante en haut a gauche de l'ecran
    pieceS = TTF_RenderText_Blended(police, "canard suivant", couleurNoire);
    position.x = 15 * TAILLE_SPRITE ;
    position.y = 5 *TAILLE_SPRITE;
    SDL_BlitSurface(pieceS, NULL, sj.ecran, &position);  //Blit du texte par-dessus

    for(y=0 ; y<4 ; y++)
    {
        for(x=0 ; x<4 ; x++)
        {
            if((SPiece[jeuGetPiece_suivante(sj.jeu)][1][y*4+x] != '0'))
                {
                 switch(jeuGetPiece_suivante(sj.jeu)) // l'image depend de la forme de la piece
                        {
                            case 0 :
                                SDL_apply_surface( sj.piece1, sj.ecran,(16+x)*TAILLE_SPRITE, (1+y)*TAILLE_SPRITE);
                                break;

                            case 1 :
                                SDL_apply_surface( sj.piece2, sj.ecran,(16+x) *TAILLE_SPRITE, (1+y)*TAILLE_SPRITE);
                                break;

                            case 2 :
                                SDL_apply_surface( sj.piece3, sj.ecran,(16+x) *TAILLE_SPRITE, (1+y)*TAILLE_SPRITE);
                                break;

                            case 3 :
                                SDL_apply_surface( sj.piece4, sj.ecran,(16+x) *TAILLE_SPRITE, (1+y)*TAILLE_SPRITE);
                                break;

                            case 4 :
                                SDL_apply_surface( sj.piece5, sj.ecran,(16+x) *TAILLE_SPRITE, (1+y)*TAILLE_SPRITE);
                                break;

                            case 5 :
                                SDL_apply_surface( sj.piece6, sj.ecran,(16+x) *TAILLE_SPRITE, (1+y)*TAILLE_SPRITE);
                                break;

                            case 6 :
                                SDL_apply_surface( sj.piece7, sj.ecran,(16+x) *TAILLE_SPRITE, (1+y)*TAILLE_SPRITE);
                                break;
                        }
                }
        }
    }

//pour afficher le score
    Score = TTF_RenderText_Blended(police, "Score : ", couleurNoire);
    position.x = 15 * TAILLE_SPRITE ;
    position.y = 12 *TAILLE_SPRITE;
    SDL_BlitSurface(Score, NULL, sj.ecran, &position);

    sprintf(text, "%d",GetScore(sj.jeu.Score));
    Score2 = TTF_RenderText_Blended(police,text, couleurNoire);
    position.x = 20 * TAILLE_SPRITE ;
    position.y = 12 *TAILLE_SPRITE;
    SDL_BlitSurface(Score2, NULL, sj.ecran, &position);  //Blit du texte par-dessus

//pour le nombre de lignes finies
    NbrLigne = TTF_RenderText_Blended(police, "Lignes : ", couleurNoire);
    position.x = 15 * TAILLE_SPRITE ;
    position.y = 14 *TAILLE_SPRITE;
    SDL_BlitSurface(NbrLigne, NULL, sj.ecran, &position);  //Blit du texte par-dessus

    sprintf(text, "%d",GetNbreLigne(sj.jeu.Score) );
    NbrLigne2 = TTF_RenderText_Blended(police,text, couleurNoire);
    position.x = 20 * TAILLE_SPRITE ;
    position.y = 14 *TAILLE_SPRITE;
    SDL_BlitSurface(NbrLigne2, NULL, sj.ecran, &position);  //Blit du texte par-dessus


//pour le niveau
    Niveau = TTF_RenderText_Blended(police, "Niveau : ", couleurNoire);
    position.x = 15 * TAILLE_SPRITE ;
    position.y = 16 *TAILLE_SPRITE;
    SDL_BlitSurface(Niveau, NULL, sj.ecran, &position);  //Blit du texte par-dessus

    sprintf(text, "%d",GetNiveau(sj.jeu.Score) );
    Niveau2 = TTF_RenderText_Blended(police,text, couleurNoire);
    position.x = 20 * TAILLE_SPRITE ;
    position.y = 16 *TAILLE_SPRITE;
    SDL_BlitSurface(Niveau2, NULL, sj.ecran, &position);  //Blit du texte par-dessus


// arret de la police
    TTF_CloseFont(police);
    TTF_CloseFont(police2);
}

void sdljeuBoucle(sdlJeu& sj)
{
	SDL_Event event;
	bool continuer = false;
	bool pause = false;
	int posX = 88;
	int tempsPrecedent = 0, tempsActuel = 0;

	adljeuAff( sj,pause );
	assert( SDL_Flip( sj.ecran )!=-1 );

    FSOUND_STREAM *musique = NULL;
    FSOUND_SAMPLE *coin = NULL;
    FSOUND_SAMPLE *pan = NULL;

//initialisation de la musique (chargement du son)
    musique = FSOUND_Stream_Open("./data/theme.mp3", FSOUND_LOOP_NORMAL, 0, 0);
    assert(musique!=NULL);
    coin = FSOUND_Sample_Load(FSOUND_FREE, "./data/Quack.mp3", 0, 0, 0);
    assert(coin!=NULL);
    pan = FSOUND_Sample_Load(FSOUND_FREE, "./data/pan.wav", 0, 0, 0);
    assert(pan!=NULL);
    FSOUND_Stream_SetLoopCount(musique, -1); // On active la répétition de la musique à l'infini
    FSOUND_Stream_Play(FSOUND_FREE, musique); // On joue la musique
    FSOUND_SetVolume(FSOUND_ALL, 150); //On augmente le son (0 minimun et 255 maximun)

	// tant que ce n'est pas la fin ...
	while ( continuer == false )
	{
		// tant qu'il y a des evenements à traiter : cette boucle n'est pas bloquante
		while ( SDL_PollEvent( &event ) )
		{
			// Si l'utilisateur a cliqué sur la croix de fermeture
			if ( event.type == SDL_QUIT )
			{
			    continuer = true;
			}
			if ( event.type == SDL_KEYDOWN )// Si une touche est enfoncée
			{
				switch ( event.key.keysym.sym )
				{
                    case SDL_QUIT: // Si c'est un évènement QUITTER
                                continuer = 0; // On met le booléen à 0, donc la boucle va s'arrêter
                                FSOUND_Stream_Close(musique);
                                FSOUND_Sample_Free(coin);
                                FSOUND_Sample_Free(pan);
                                break;
                    case SDLK_ESCAPE: // Appui sur la touche Echap, on arrête le programme
                                FSOUND_Stream_Close(musique);
                                FSOUND_Sample_Free(coin);
                                FSOUND_Sample_Free(pan);
                                continuer =true;
                        break;
                    case SDLK_UP:
                        if(pause == false)
                        {
                            jeuActionClavier( sj.jeu, 'r'); //rotation
                        }
                        break;
                    case SDLK_DOWN:
                        if(pause == false)
                        {
                            jeuActionClavier( sj.jeu, 't'); // descend
                        }
                        break;
                    case SDLK_LEFT:
                        if(pause == false)
                        {
                            posX = jeuGetPosX(sj.jeu);
                            jeuActionClavier( sj.jeu, 'g'); // gauche
                            if(jeuGetPosX(sj.jeu) == posX) // si on est contre le mur gauche et qu'on veut aller a gauche
                            {
                                FSOUND_PlaySound(FSOUND_FREE, coin); // fait un coin
                            }
                        }
                        break;
                    case SDLK_SPACE:
                        jeuActionClavier( sj.jeu, 's'); // descend d'un coup
                        break;
                    case SDLK_RIGHT:
                        if(pause==false)
                        {
                            posX=jeuGetPosX(sj.jeu);
                            jeuActionClavier( sj.jeu, 'd'); //droite
                            if(jeuGetPosX(sj.jeu)==posX) // si on est deja le plus a droite, et qu'on veut encore se decaler d'un cran
                            {
                                FSOUND_PlaySound(FSOUND_FREE, coin);
                            }
                        }
                        break;
                    case SDLK_p: // Appui sur la touche p, on met le programme en pause
                        pause =!(pause);
                        break;
                    default: break;
				}
			}
		}
		tempsActuel = SDL_GetTicks();
    if (tempsActuel - tempsPrecedent > 500-50*GetNiveau(sj.jeu.Score)) // Si 500 ms se sont écoulées moins 50 fois le niveau
    {
		if(pause == false)
        {
            descentePiece(sj.jeu);
        }
        tempsPrecedent = tempsActuel; /* Le temps "actuel" devient le temps "precedent" pour nos futurs calculs */
    }
    if(sj.jeu.finJeu)
    {
	    FSOUND_PlaySound(FSOUND_FREE, pan);
        FSOUND_Stream_Close(musique);
        FSOUND_Sample_Free(coin);
        FSOUND_Sample_Free(pan);

	    break;
    }
		// on affiche le jeu sur le buffer caché
        adljeuAff( sj,pause );
		// on permute les deux buffers (cette fonction ne doit se faire qu'une seule fois dans a boucle)
		SDL_Flip( sj.ecran );
//		FSOUND_Stream_Close(musique);
	}
}


void sdljeuDetruit( sdlJeu& sj)
{
	SDL_FreeSurface( sj.piece1 );
	SDL_FreeSurface( sj.piece2 );
	SDL_FreeSurface( sj.piece3 );
	SDL_FreeSurface( sj.piece4 );
	SDL_FreeSurface( sj.piece5 );
	SDL_FreeSurface( sj.piece6 );
	SDL_FreeSurface( sj.piece7 );
	SDL_FreeSurface( sj.mur );
	SDL_FreeSurface( sj.ecran );
	SDL_FreeSurface( sj.terrain);
	SDL_FreeSurface( sj.pause);
}


SDL_Surface *SDL_load_image(const char* filename )
{
	SDL_Surface* loadedImage = NULL;//Temporary storage for the image that's loaded
	SDL_Surface* optimizedImage = NULL;//The optimized image that will be used
	loadedImage = SDL_LoadBMP( filename );//Load the image
	if ( loadedImage != NULL )//If nothing went wrong in loading the image
	{
		optimizedImage = SDL_DisplayFormat( loadedImage );//Create an optimized image
		SDL_FreeSurface( loadedImage );//Free the old image
	}
	return optimizedImage;//Return the optimized image
}


void SDL_apply_surface( SDL_Surface* source, SDL_Surface* destination, int x, int y )
{
	SDL_Rect offset;//Make a temporary rectangle to hold the offsets
	//Give the offsets to the rectangle
	offset.x = x;
	offset.y = y;
	SDL_BlitSurface( source, NULL, destination, &offset );//Blit the surface
}
